/*
 *  PhraseTable.cpp
 *  OfflineTranslator
 *
 *  Created by PH on 5.9.10.
 *  Copyright 2010 Petr Homola. All rights reserved.
 *
 */

#include "stdafx.h"
#include "PhraseTable.h"

namespace nlp {

	void PhraseTable::enumerateSubchains(int length, BLOCKVAR(callback, void, vector<Phrase*>*)) {
		for(map<int,vector<Phrase*>*>::const_iterator it = phrases.begin(); it != phrases.end(); ++it) {
			enumerateSubchains(it->first, length, callback);
		}
	}
	
	void PhraseTable::enumerateSubchains(int node, int length, BLOCKVAR(callback, void, vector<Phrase*>*)) const {
		vector<Phrase*>* v = phrases[node];
		if (v != NULL) for (vector<Phrase*>::const_iterator it = v->begin(); it != v->end(); ++it) {
			Phrase* phrase = *it;
			if (length == 1) {
				vector<Phrase*> result;
				result.push_back(phrase);
				callback(&result);
			} else {
				enumerateSubchains(phrase->getEnd(), length - 1, BLOCK(phrase, callback)(vector<Phrase*>* tail) {
					tail->insert(tail->begin(), phrase);
					callback(tail);
				});
			}
		}
	}
	
	unsigned int PhraseTable::enumerateShortestPaths(BLOCKVAR(callback, void, PhrasePath*)) {
		__block int minLength = INT32_MAX, length;
		__block vector<PhrasePath*>::const_iterator it;
		vector<PhrasePath*>* paths = new vector<PhrasePath*>;
		enumeratePaths(BLOCK(&length, &minLength, paths)(PhrasePath* path) {
			length = path->getLength();
			if (length < minLength) minLength = length;
			if (length == minLength) paths->push_back(path);
		}, BLOCK(&it, paths, &minLength, callback)() {
			for (it = paths->begin(); it != paths->end(); ++it) {
				if ((*it)->getLength() == minLength) callback(*it);
			}
		}, true);
		delete paths;
		return minLength;
	}
	
	void PhraseTable::enumeratePaths(BLOCKVAR(callback, void, PhrasePath*), BLOCKVAR(callback2, void), bool onlyShortest) const {
		map<int, vector<PhrasePath*>*> cache;
		int minLength = INT_MAX;
		enumeratePaths(0, &cache, callback, 1, onlyShortest ? &minLength : NULL);
		callback2();
		for(map<int,vector<PhrasePath*>*>::const_iterator it = cache.begin(); it != cache.end(); ++it) {
			vector<PhrasePath*>* v = it->second;
			for (vector<PhrasePath*>::const_iterator it2 = v->begin(); it2 != v->end(); ++it2) {
				delete *it2;
			}
			delete v;
		}	
	}
	
	void PhraseTable::enumeratePaths(int node, map<int, vector<PhrasePath*>*>* cache, BLOCKVAR(callback, void, PhrasePath*), int length, int* minLength) const {
		vector<PhrasePath*>* v = (*cache)[node];
		if (v != NULL) {
			//cout << "Using cache: " << node << endl;
			for (vector<PhrasePath*>::const_iterator it = v->begin(); it != v->end(); ++it) {
				callback(*it);
			}
		} else {
			vector<PhrasePath*>* paths = new vector<PhrasePath*>;
			(*cache)[node] = paths;
			//cout << "Added to cache: " << node << endl;
			vector<Phrase*>* v = phrases[node];
			for (vector<Phrase*>::const_iterator it = v->begin(); it != v->end(); ++it) {
				Phrase* phrase = *it;
				if (phrases[phrase->getEnd()] == NULL) {
					PhrasePath* path = new PhrasePath(phrase, NULL);
					paths->push_back(path);
					callback(path);
					if (minLength != NULL && *minLength > length) *minLength = length;
				} else {
					if (minLength != NULL && length >= *minLength) {
						//cout << "Ignoring long path" << endl;
						continue;
					}
					__block PhrasePath* path;
					enumeratePaths(phrase->getEnd(), cache, BLOCK(&path, paths, phrase, callback)(PhrasePath* tail) {
						path = new PhrasePath(phrase, tail);
						paths->push_back(path);
						callback(path);
					}, length + 1, minLength);
				}
			}
		}
	}
	
}
